﻿#ifndef QQBciSignal_H
#define QQBciSignal_H

#include <QMetaType>
#include <QSharedData>
#include <QSharedDataPointer>
#include <armadillo>

namespace bci {

// 接收信号数据的抽象类
class QBciSignal {
public:
  QBciSignal(){};
  virtual ~QBciSignal(){};
};

/*
 * 下面以Armadillo为例给出数据处理的方法
 */
// 定义数据类型
#ifndef SINGLE_PRECISION
typedef double Float;
#else
typedef float Float;
#endif

typedef arma::Mat<Float> ArmaMat;
typedef arma::Col<Float> ArmaCol;
typedef arma::Mat<std::complex<Float>> ArmaComplexMat;
typedef arma::Col<Float> ArmaVec;

class ArmaData : public QSharedData {
public:
  ArmaData(){};
  ArmaData(const ArmaData &other) : QSharedData(other), mat(other.mat) {}
  ~ArmaData(){};

  ArmaMat mat;
};

// 该类是以Armadillo
class QBciArmaSignal : public QBciSignal {

public:
  QBciArmaSignal() : d(new ArmaData) {}
  QBciArmaSignal(const QBciArmaSignal &other) : d(other.d) {}
  QBciArmaSignal(const arma::uword in_rows, const arma::uword in_cols)
      : QBciArmaSignal() {
    d->mat = ArmaMat(in_rows, in_cols);
  }
  template <typename fill_type>
  QBciArmaSignal(const arma::uword in_rows, const arma::uword in_cols,
                 const arma::fill::fill_class<fill_type> &f)
      : QBciSignal() {
    d->mat = ArmaMat(in_rows, in_cols, f);
  }

  QBciArmaSignal(const ArmaMat &src) : QBciArmaSignal() { d->mat = src; }
  QBciArmaSignal(ArmaMat &&src) : QBciArmaSignal() { d->mat = src; }

  QBciArmaSignal &operator=(const QBciArmaSignal &sig) {
    d->mat = sig.d->mat;
    return *this;
  }
  QBciArmaSignal &operator=(QBciArmaSignal &&sig) {
    d->mat = std::move(sig.d->mat);
    return *this;
  }

  /*!
   * \brief n_channels 返回信号的通道数
   */
  int n_channels() const { return d->mat.n_cols; }
  /*!
   * \brief n_lengths 返回信号数据点数
   */
  int n_lengths() const { return d->mat.n_rows; }

  /*!
   * \brief cat 拼接相同通道数的信号到本信号
   * \param sig
   */
  void cat(const QBciArmaSignal &sig) {
    d->mat = arma::join_cols(d->mat, sig.d->mat);
  }

  /*!
   * \brief channelsf
   * \return
   */
  QBciArmaSignal channels(const arma::uword &firstChannel,
                          const arma::uword &lastChannel) const;

  QBciArmaSignal data(const arma::uword &firstData,
                      const arma::uword &lastData) const;

  QSharedDataPointer<ArmaData> d;
};

} // namespace bci

// 因为BciArmaSignal只有一个数据成员所以可以用Q_DECLARE_TYPEINFO
// 进行定义定义为MOVABLE，使其能够在Qt容器中使用
Q_DECLARE_TYPEINFO(bci::QBciArmaSignal, Q_MOVABLE_TYPE);

inline std::fstream &operator<<(std::fstream &fs,
                                const bci::QBciArmaSignal &data) {
  for (auto i = 0; i < data.n_lengths(); ++i) {
    for (auto j = 0; j < data.n_channels(); ++j) {
      fs << data.d->mat(i, j);
      if (j != data.n_channels() - 1)
        fs << ", ";
    }
    fs << "\n";
  }
  return fs;
}

#endif // QBciSignal_H
